#include <errno.h>
#include <signal.h>
#include <cstring>
#include <stdexcept>
#include "Wrappers/UnixUtils/Process.hpp"

namespace wrappers {
namespace unix_utils {

Process &Process::GetInstance() {
  static Process singleton;

  return (singleton);
}

Process::Process() {
  mIsAFork = false;
  mPID = getpid();
  mArgc = 0;
  mArgv = NULL;
  mEnvp = NULL;
  mChildFunction = NULL;
}

Process::~Process() {
}

bool Process::operator==(const Process& compareWith) const {
  return (mPID == compareWith.mPID);
}

bool Process::operator!=(const Process& compareWith) const {
  return (!operator==(compareWith));
}

void Process::Fork() {
  pid_t pid;

  if ((pid = fork()) == -1)
    throw std::runtime_error("Process::Fork: fork syscall has failed"
	+ std::string(strerror(errno)));
  if (pid == 0) {
    mForksList.erase(mForksList.begin(), mForksList.end());
    mIsAFork = true;
    mPID = pid;
    if (mChildFunction != NULL)
    mChildFunction();
  }
  else {
    mForksList.push_back(pid);
  }
}
void Process::KillChildren() {
  std::list<pid_t>::const_iterator it;

  for (it = mForksList.begin(); it != mForksList.end(); ++it) {
    kill(*it, SIGTERM);
  }
}

Process &Process::SetChildFunction(const ChildFunction &function) {
  mChildFunction = function;
  return *this;
}

Process &Process::RemoveChildFunction() {
  mChildFunction = NULL;
  return *this;
}

bool Process::IsAFork() const {
  return mIsAFork;
}

int Process::GetArgc() const {
  return mArgc;
}

char** Process::GetArgv() const {
  return mArgv;
}

char** Process::GetEnvp() const {
  return mEnvp;
}

} /* !namespace unix_utils */
} /* !namespace wrappers */
